﻿using System;
using System.IO;

public class NES
{
    internal int cc;
    public CPU cpu;
    public Memory cpuMem;
    public GameGenie gameGenie;
    public UI gui;
    internal bool isRunning_Renamed_Field;
    public MemoryMapper memMapper;
    public PaletteTable palTable;
    public PAPU papu;
    public PPU ppu;
    public Memory ppuMem;
    public ROM rom;
    public string romFile;
    public ByteBuffer saveState;
    public Memory sprMem;

    public NES(UI gui)
    {
        Globals.nes = this;
        this.gui = gui;
        this.cpuMem = new Memory(this, 0x10000);
        this.ppuMem = new Memory(this, 0x8000);
        this.sprMem = new Memory(this, 0x100);
        this.cpu = new CPU(this);
        this.palTable = new PaletteTable();
        this.ppu = new PPU(this);
        this.papu = new PAPU(this);
        this.gameGenie = new GameGenie();
        for (int i = 0; i < 20; i++)
        {
            if (i == 0x10)
            {
                this.papu.writeReg(0x4010, 0x10);
            }
            else
            {
                this.papu.writeReg(0x4000 + i, 0);
            }
        }
        this.palTable.loadDefaultPalette();
        this.cpu.init();
        this.ppu.init();
        this.enableSound(Globals.enableSound);
        this.clearCPUMemory();
    }

    public virtual void clearCPUMemory()
    {
        short memoryFlushValue = Globals.memoryFlushValue;
        for (int i = 0; i < 0x2000; i++)
        {
            this.cpuMem.mem[i] = memoryFlushValue;
        }
        for (int j = 0; j < 4; j++)
        {
            int num4 = j * 0x800;
            this.cpuMem.mem[num4 + 8] = 0xf7;
            this.cpuMem.mem[num4 + 9] = 0xef;
            this.cpuMem.mem[num4 + 10] = 0xdf;
            this.cpuMem.mem[num4 + 15] = 0xbf;
        }
    }

    public virtual void destroy()
    {
        if (this.cpu != null)
        {
            this.cpu.destroy();
        }
        if (this.ppu != null)
        {
            this.ppu.destroy();
        }
        if (this.papu != null)
        {
            this.papu.destroy();
        }
        if (this.cpuMem != null)
        {
            this.cpuMem.destroy();
        }
        if (this.ppuMem != null)
        {
            this.ppuMem.destroy();
        }
        if (this.sprMem != null)
        {
            this.sprMem.destroy();
        }
        if (this.memMapper != null)
        {
            this.memMapper.destroy();
        }
        if (this.rom != null)
        {
            this.rom.destroy();
        }
        this.gui = null;
        this.cpu = null;
        this.ppu = null;
        this.papu = null;
        this.cpuMem = null;
        this.ppuMem = null;
        this.sprMem = null;
        this.memMapper = null;
        this.rom = null;
        this.gameGenie = null;
        this.palTable = null;
    }

    public virtual void enableSound(bool enable)
    {
        bool running = this.Running;
        if (running)
        {
            this.stopEmulation();
        }
        if (enable)
        {
            this.papu.start();
        }
        else
        {
            this.papu.stop();
        }
        Globals.enableSound = enable;
        if (running)
        {
            this.startEmulation();
        }
    }

    public virtual bool loadRom(Stream file)
    {
        if (this.isRunning_Renamed_Field)
        {
            this.stopEmulation();
        }
        this.rom = new ROM(this);
        this.rom.load(file);
        if (this.rom.Valid)
        {
            this.reset();
            this.memMapper = this.rom.createMapper();
            this.memMapper.init(this);
            this.cpu.Mapper = this.memMapper;
            this.memMapper.loadROM(this.rom);
            this.ppu.Mirroring = this.rom.MirroringType;
            if (this.gameGenie.CodeCount > 0)
            {
                this.memMapper.setGameGenieState(true);
            }
            this.romFile = "";
        }
        return this.rom.Valid;
    }

    public virtual void reloadRom()
    {
        string romFile = this.romFile;
    }

    public virtual void reset()
    {
        if (this.rom != null)
        {
            this.rom.closeRom();
        }
        if (this.memMapper != null)
        {
            this.memMapper.reset();
        }
        this.cpuMem.reset();
        this.ppuMem.reset();
        this.sprMem.reset();
        this.clearCPUMemory();
        this.cpu.reset();
        this.cpu.init();
        this.ppu.reset();
        this.palTable.reset();
        this.papu.reset();
        InputHandler handler = this.gui.Joy1;
        if (handler != null)
        {
            handler.reset();
        }
    }

    public virtual void startEmulation()
    {
        if (Globals.enableSound && !this.papu.isRunning)
        {
            this.papu.start();
        }
        if ((this.rom != null) && this.rom.Valid)
        {
            this.isRunning_Renamed_Field = true;
        }
    }

    public virtual void stateLoad()
    {
        if (this.cpu.Emulating)
        {
            this.cpu.loading = true;
        }
        else
        {
            bool flag = false;
            flag = true;
            this.stopEmulation();
            if (this.saveState != null)
            {
                this.saveState.goTo(0);
                if (this.saveState.readByte() == 1)
                {
                    this.cpuMem.stateLoad(this.saveState);
                    this.ppuMem.stateLoad(this.saveState);
                    this.sprMem.stateLoad(this.saveState);
                    this.cpu.stateLoad(this.saveState);
                    this.memMapper.stateLoad(this.saveState);
                    this.ppu.stateLoad(this.saveState);
                    this.papu.stateLoad(this.saveState);
                }
            }
            if (flag)
            {
                this.startEmulation();
            }
        }
    }

    public virtual void stateSave()
    {
        if (this.cpu.Emulating)
        {
            this.cpu.saving = true;
        }
        else
        {
            this.saveState = new ByteBuffer(1, 0);
            bool flag = true;
            this.stopEmulation();
            this.saveState.putByte(1);
            this.cpuMem.stateSave(this.saveState);
            this.ppuMem.stateSave(this.saveState);
            this.sprMem.stateSave(this.saveState);
            this.cpu.stateSave(this.saveState);
            this.memMapper.stateSave(this.saveState);
            this.ppu.stateSave(this.saveState);
            if (flag)
            {
                this.startEmulation();
            }
        }
    }

    public virtual void stopEmulation()
    {
        this.isRunning_Renamed_Field = false;
    }

    public virtual CPU Cpu
    {
        get
        {
            return this.cpu;
        }
    }

    public virtual Memory CpuMemory
    {
        get
        {
            return this.cpuMem;
        }
    }

    public virtual int Framerate
    {
        set
        {
            Globals.preferredFrameRate = value;
            Globals.frameTime = 0xf4240 / value;
            this.papu.setSampleRate(this.papu.getSampleRate(), false);
        }
    }

    public virtual GameGenie GameGenie
    {
        get
        {
            return this.gameGenie;
        }
    }

    public virtual bool GameGenieState
    {
        set
        {
            if (this.memMapper != null)
            {
                this.memMapper.setGameGenieState(value);
            }
        }
    }

    public virtual UI Gui
    {
        get
        {
            return this.gui;
        }
    }

    public virtual MemoryMapper MemoryMapper
    {
        get
        {
            return this.memMapper;
        }
    }

    public virtual PAPU Papu
    {
        get
        {
            return this.papu;
        }
    }

    public virtual PPU Ppu
    {
        get
        {
            return this.ppu;
        }
    }

    public virtual Memory PpuMemory
    {
        get
        {
            return this.ppuMem;
        }
    }

    public virtual ROM Rom
    {
        get
        {
            return this.rom;
        }
    }

    public virtual bool Running
    {
        get
        {
            return this.isRunning_Renamed_Field;
        }
    }

    public virtual Memory SprMemory
    {
        get
        {
            return this.sprMem;
        }
    }
}

